docs(guide): author the page-mode navigate actions where the renderer reads them (objectui#7440) - #7865
Merged
os-sam merged 1 commit intoSep 6, 2026
Conversation
… reads them (objectui#7440)
`record-edit-modes.md` taught three `action:button` examples that put the
action name in a nested `action` bag. `action-button.tsx` never reads
`schema.action`: it forwards `type: schema.actionType` and `params:
schema.params`, and `ActionRunner.execute` dispatches on
`action.type || action.actionType || action.name`. The documented shape
therefore forwarded `type: undefined` and matched no handler — a button
that rendered, clicked, and did nothing.
The `navigate_create` / `navigate_edit` handlers are live
(`AppContent.tsx:475,487`); only the authoring shape was wrong. Each
example is repaired for what it was demonstrating:
- example 1 (`navigate_create` with an explicit object): mis-authored,
rewritten to `actionType` + top-level `params`.
- example 2 (`navigate_edit`): same rewrite, and its `${record.id}`
replaced with a literal id. Measured: `params` is not template-
evaluated on any authoring channel, and `action:button` does not
inject the surrounding row (`DeclaredActionsBar.tsx:110`), so the
template arrived at the handler verbatim.
- example 3 (context-supplied object): demonstrates omitting the
arguments, so the repair keeps `params` absent rather than filling it
in.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KbJQ1y1J12nZxYzFWhP8Q3
This was referenced Sep 6, 2026
os-sam
marked this pull request as ready for review
September 6, 2026 00:44
os-sam
deleted the
claude/issue-7440-record-edit-modes-nested-action-bag
branch
September 6, 2026 01:21
This was referenced Sep 6, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #7440
content/docs/guide/record-edit-modes.mdtaught threeaction:buttonexamples that put the action name inside a nestedactionbag. Nothing reads that key. This rewrites all three into the shape a renderer actually reads, derived from the code and verified by rendering the published snippets.⭐ The handlers are live and untouched.
navigate_create/navigate_editreally are registered atpackages/app-shell/src/console/AppContent.tsx:475,487. Nothing in this PR deletes, retires or re-registers them. Only the doc page changed — one file, 24 insertions, 15 deletions.Where the working shape came from (code, not the card)
packages/components/src/renderers/action/action-button.tsx:160type: schema.actionType— andschema.actionis read nowhere in the fileaction-button.tsx:126-128,173params: schema.params(object) oractionParams(array)packages/core/src/actions/ActionRunner.ts:972action.type || action.actionType || action.nameActionRunner.ts:1064this.handlers.has(actionType)packages/app-shell/src/utils/recordFormNavigation.ts:271,300action.params?.objectName,action.params?.recordId⇒ the authored channel is
actionTypefor the handler name and a top-levelparamsobject for its arguments. The nested bag forwardstype: undefinedand matches no handler: the button renders, is clickable, does nothing.Positive control, in-repo and live:
packages/components/src/renderers/action/__tests__/action-forward-precedence.test.tsx:67-82pins exactly that composition (actionType+ top-levelparams), andpackages/components/src/__tests__/action-bodyExtra-forward.test.tsx:88-95authors anaction:buttonthe same way. Both are green today.Before / after, per example
1.
navigate_createwith an explicit object — mis-authored, mechanical rewrite{ "type": "action:button", "label": "New Account", "icon": "plus", - "action": { - "action": "navigate_create", - "params": { "objectName": "account" } - } + "actionType": "navigate_create", + "params": { "objectName": "account" } }2.
navigate_edit— same rewrite, plus its record id had a second defect{ "type": "action:button", "label": "Edit", "icon": "pencil", - "action": { - "action": "navigate_edit", - "params": { - "objectName": "account", - "recordId": "${record.id}" - } + "actionType": "navigate_edit", + "params": { + "objectName": "account", + "recordId": "0015e000abcd" } }A purely mechanical rewrite here would have published a second silently-inert example. Measured through the real renderers, with a live record bound:
The
propertieshoist evaluates per value and shallowly, so a template nested one level inside aparamsobject is never reached — andaction:buttondeliberately does not inject the surrounding row (packages/app-shell/src/views/DeclaredActionsBar.tsx:110: "injects the record underparams._rowRecord— whichaction:buttondoes NOT do"), whileresolveNavigateEditUrlhas no context fallback forrecordIdby design (recordFormNavigation.ts:286-287). So from metadata the id can only be a literal. The example now says so, and points per-row Edit at the built-in entry point the page already documents.3. context-supplied object — demonstrating a capability, so the repair keeps the omission
{ "type": "action:button", "label": "New", - "action": { "action": "navigate_create" } + "actionType": "navigate_create" }The point of this one is that
paramsmay be omitted and the action context suppliesobjectName(recordFormNavigation.ts:271, last precedence step). Filling in aparamsbag to "make it work" would have deleted what it teaches. It stays absent.⭐ Why nothing went red — measured, not assumed
The three blocks are ```jsonc fences. Exactly one instrument reads them, and it reads one key.
scripts/check-doc-component-types.mjswalks every fence incontent/docs/**regardless of language and collectstypesites with a regex accepting"type",'type', or a baretypeguarded by a negative lookbehind on word characters,$and.(line 1085 of that file) — so it saw"type": "action:button", judged it registered, and passed. Its own header states the limit verbatim: "NOT in scope, deliberately: whether the snippet's OTHER keys are read by the renderer the type resolves to."Two mutations on the pristine tree, each proved on disk before the run and restored to the HEAD blob after:
M2 names this file, these three blocks, and reports their fence as
jsonc— so the instrument is alive on exactly the blocks in question and blind to exactly the key that was wrong. The gate's counters are byte-identical before and after this PR's repair, which is the same fact from the other side.⛔ No gate is added here. objectui#7851 is in flight and is exactly that report-only sweep of non-type keys in
content/docs/**json fences; this page is a known corpus point for it — the three blocks arejsonc, notjson, which that sweep's fence-language set should cover.Evidence
Union re-run after the final commit, at
de0205717, worktree clean. Exit codes captured by redirecting first, never through a pipe; verdicts quoted from each gate's own line.pnpm check:doc-types✅ Every documented component type is registered.pnpm check:doc-fences✅ check:doc-fences — every TypeScript block in 227 document(s) is fenced ts/tsx/typescript …pnpm check:doc-snippetsEvery covered documentation snippet compiles against the built types.(456 of 456 blocks judged, 0 failed)pnpm check:control-bytes✅ check-control-bytes: OK (scanned 6367 tracked text file(s); skipped 85 binary).pnpm check:shell-escape-residue✅ check-shell-escape-residue: OK (5/5 root(s) resolved … content/docs: 184 file(s), 1065 fence(s) …)pnpm docs:check-linksLinks are valid across 17 scan roots.pnpm check:docs-route-closure✅ all 13 packages named in … registerCatalogBlocks.ts are accounted fornode scripts/check-changeset-presence.mjs✅ No source or published contract of a released package changed in this range, so no changeset is owed.check:doc-snippetsfirst returned EXIT=2 — PRECONDITION NOT MET (unbuilt packages). That is "I could not run", not a red gate, so it is not reported as one: the scoped closure was built first (pnpm exec turbo run build $(node scripts/check-doc-snippet-types.mjs --build-filter) --concurrency=2— 34/34 tasks, 4m22s, exit 0) and the gate re-run for the real reading above.Runtime verification of the published snippets. A throwaway probe read the three ```jsonc blocks back out of the committed file,
JSON.parsed them, and rendered each through `SchemaRenderer` with `navigate_create` / `navigate_edit` registered the way `AppContent.tsx` registers them:and the negative control, the shape the page taught before this PR:
The probe files were deleted before the commit;
git status --porcelainis empty and the diff is one file. Downstream of the forward,packages/app-shell/src/utils/__tests__/recordFormNavigation.test.ts(37 tests) passes unchanged — that is the suite that turnsaction.paramsinto the URLs this page documents.Not run, and why: the full
pnpm testandpnpm lintfarms (CI owns them; this diff is one markdown file and adds no code), and the remaining 30-oddcheck:*gates whose inputs (package source, manifests, i18n bundles, skills, spec symbols) this diff does not touch.Scope
Clause-② stays
no: no new authorable key, no handler-registration change, no gate change, no renderer change. One file.Two findings outside this card's surface were filed rather than repaired here — see the comment on #7440.
Generated by Claude Code